Contexto

Teste

Análise

Leitura do conjunto de dados

```r
df <- readxl::read_excel('./mobile_app_user_dataset_1.xlsx')[-1,]

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### Exploração

> Uma vez que é uma pesquisa sobre *mobile devices*, veremos qual a proporção de pessoas que de fato possuem um *device*.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuXG5kZiAlPiUgXG4gIHNlbGVjdChRMikgJT4lIFxuICBkcm9wX25hKCkgJT4lIFxuICBtdXRhdGUoXG4gICAgUTIgPSBjYXNlX3doZW4oXG4gICAgICBRMiA9PSAxIH4gXFxQb3NzdWlcXCxcbiAgICAgIFEyICE9IDEgfiBcXE7Dg8KjbyBQb3NzdWlcXFxuICAgIClcbiAgKSAlPiUgXG4gIGdncGxvdChcbiAgICBhZXMoXG4gICAgICB5ID0gUTIsXG4gICAgICBmaWxsID0gUTJcbiAgICApXG4gICkgK1xuICBnZW9tX2JhcihcbiAgICBwb3NpdGlvbiA9IFxcZG9kZ2VcXCxcbiAgKSArXG4gIGdlb21fbGFiZWwoXG4gICAgICBzdGF0ID0gJ2NvdW50JyxcbiAgICAgIGFlcyhcbiAgICAgICAgbGFiZWwgPSAuLmNvdW50Li4sXG4gICAgICApLFxuICAgICAgY29sb3IgPSAnd2hpdGUnLFxuICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRVxuICApICsgXG4gIGxhYnMoXG4gICAgeSA9IFxcXFwsXG4gICAgeCA9IFxcVG90YWwgZGUgUGVzc29hc1xcLFxuICAgIHRpdGxlID0gXFxEaXN0cmlidWnDg8Knw4PCo28gZGUgcGVzc29hcyBxdWUgdGVtIG91IG7Dg8KjbyBjZWx1bGFyXFwsXG4gICAgc3VidGl0bGUgPSBcXERhZG9zIG9yaXVuZG9zIGRhIHBlc3F1aXNhIHJlYWxpemFkYSBwZWxhIEhhcnZhcmRcXFxuICApICtcbiAgc2NhbGVfZmlsbF9tYW51YWwoXG4gICAgdmFsdWVzID0gYyggXFwjQzQxNjFDXFwsIFxcIzAwOTQ5MVxcKSxcbiAgKSArXG4gIHRoZW1lX2NsYXNzaWMoKSArXG4gIHRoZW1lKFxuICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dCh2anVzdD0tLjIsIHNpemU9MTEpLFxuICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKVxuICApIFxuXG5gYGBcbmBgYCJ9 -->

```r
```r

df %>% 
  select(Q2) %>% 
  drop_na() %>% 
  mutate(
    Q2 = case_when(
      Q2 == 1 ~ \Possui\,
      Q2 != 1 ~ \Não Possui\
    )
  ) %>% 
  ggplot(
    aes(
      y = Q2,
      fill = Q2
    )
  ) +
  geom_bar(
    position = \dodge\,
  ) +
  geom_label(
      stat = 'count',
      aes(
        label = ..count..,
      ),
      color = 'white',
      show.legend = FALSE
  ) + 
  labs(
    y = \\,
    x = \Total de Pessoas\,
    title = \Distribuição de pessoas que tem ou não celular\,
    subtitle = \Dados oriundos da pesquisa realizada pela Harvard\
  ) +
  scale_fill_manual(
    values = c( \#C4161C\, \#009491\),
  ) +
  theme_classic() +
  theme(
    axis.title.x = element_text(vjust=-.2, size=11),
    legend.title = element_blank()
  ) 



Podemos visualizar que a grande parte das pessoas possuem celular.


A proporção de pessoas que não tem é de 12%.


Visualizaremos agora os diferentes tipos de dispositivos utilizados pelos usuários que possuem celular


phone_format <- function (phone_list, phone_type, apply_function = function(param) param) {
  phone_dic = list(
    apple = c(\apple\, \iphone\, \ipad\, \aple\, \appale\, \ipod\, \aplle\, \i-phone\, \ipone\, \applke\, \applr\, \appme\, \iphon\),
    blackberry = c(\blackberry\, \blackb\, \blackeb\, \baclkberry\, \blakckberry\, \blacberry\, \blakberry\, \blackerry\, \bleckberry\),
    samsung = c(\samsung\, \samsumg\, \sansung\, \sumsung\, \samsug\, \samsun\,  \samgung\, \samsing\, \samung\, \sansug\, \samasung\, \samsang\, \samsong\, \sumsang\, \galaxynote\),
    null = c(\\\?\, \9000\, \930p\),
    sony_ericsson = c(\sony-\, \sonyer\, \sony\, \erison\),
    nokia = c(\nokia\, \nokya\),
    asus = c(\asus\),
    acer = c(\acer\)
  ) 
  
  
  str_detect(phone_list, paste(phone_dic[[phone_type]], collapse = \|\)) ~ apply_function(phone_type)
}

phones <- df %>%
  filter(Q2 == 1) %>% 
  select(Q3_1_TEXT) %>% 
  drop_na() %>% 
  mutate(
    Q3 = str_replace(str_to_lower(Q3_1_TEXT), \ \, \\)
  ) %>% 
  mutate(
    Q3 = case_when(
      phone_format(Q3, \apple\),
      phone_format(Q3, \samsung\),
      phone_format(Q3, \blackberry\),
      phone_format(Q3, \null\),
      phone_format(Q3, \sony_ericsson\, function(param) str_replace(param, \_\, \ \)),
      TRUE ~ Q3
    )
  ) %>% 
  group_by(Q3) %>% 
  count() %>%
  arrange(desc(n)) 

phones
length(names(df))
[1] 161
df

q5_answers <- data.frame(
  row.names = c(1, 2, 3, 4, 5, 6, 7, 8, 9),
  val = c(\Never\, \Less than once a month \, \Once a month\, \More than once a month\, \Once a week\, \More than once a week\, \Once a day\, \Several times a day\, \Other\)
)

df %>% 
  select(Q5) %>% 
  drop_na() %>% 
  mutate(
    Q5_TEXT = qr_answers[Q5, ]
  ) %>% 
  group_by(Q5_TEXT) %>% 
  count() %>% 
  arrange(desc(n)) %>% 
  ggplot(
    aes(
      x = reorder(Q5_TEXT, -n),
      y = n,
      fill = Q5_TEXT
    )
  ) +
  geom_col() +
  labs(
    x = 'Frequencia de abertura da loja de aplicativos',
    y = 'Total'
  ) +
  theme(
    axis.text.x = element_text(angle = 45, vjust=.6),
  )

NA

q6_answers <- data.frame(
  row.names = c(1, 2, 3, 4, 5, 6),
  val = c("0 - 1", "2 - 5", "6 - 10", "11 - 20", "21 - 30", "Mais de 30")
)


df %>% 
  select(Q6) %>% 
  drop_na() %>% 
  mutate(
    Q6_TEXT = q6_answers[Q6,]
  ) %>% 
  group_by(Q6_TEXT) %>% 
  count() %>% 
  ggplot(
    aes(
      x = reorder(Q6_TEXT, -n),
      y = n,
      fill = Q6_TEXT
    )
  ) +
  geom_col() +
  labs(
    x = 'Quantidade de aplicativos baixados por mês',
    y = 'Total',
  ) +
  theme_classic() +
  labs(
    fill = 'Frequência'
  ) +
  theme(
    axis.text.x = element_text(vjust = -1),
    axis.title.x = element_text(vjust = -1),
  )

Vamos ver se a galera que mais baixa é a galera que mais acessa a loja


df %>% 
  select(Q5, Q6) %>% 
  drop_na() %>% 
  mutate(
    Q5 = q5_answers[Q5,],
    Q6 = q6_answers[Q6, ]
  ) %>% 
  group_by(Q5, Q6) %>% 
    count() %>% 
  arrange(desc(n)) %>% 
  ggplot(
    aes(
      y = reorder(Q5, -n),
      x = n,
      fill = Q6
    )
  ) +
  geom_bar(
    stat = "identity",
    position = position_dodge(width = 1)
  ) +
  geom_label(
    aes(
      label = n,
    ),
    size = 3
  ) +
  labs(
    y = 'Frequência de acesso à loja de aplicativos',
    x = 'Total'
  ) +
  theme(
    axis.text.x = element_text(angle = 20, vjust = 0.5),
  ) +
  facet_grid(rows = 'Q6')

Definindo função genéricas para contagem e plotagem de dummy vars

arrange_and_plot <- function(df, 
                             cols, 
                             named_cols,
                             desc_col = \reason\, 
                             legend.position = \none\,
                             title = \\,
                             xlabel = \\,
                             ylabel = \\,
                             show.legend = FALSE,
                             col.width = 0.5,
                             dodge.width = 0.5,
                             xaxis.title.size = 13,
                             xaxis.title.vjust = 0.5,
                             yaxis.title.size = 13,
                             yaxis.title.vjust = 0,
                             xaxis.text.angle = 0,
                             xaxis.text.vjust = 0,
                             invert.axis = FALSE,
                             hide.yaxis.title = FALSE,
                             hide.xaxis.title = FALSE
                             ) {
  rdf <- df %>% 
    select(cols) %>% 
    rowwise() %>% 
    sapply(as.numeric) %>% 
    as.tibble() %>% 
    rowwise() %>% 
    replace(is.na(.), 0) %>% 
    rowwise() %>% 
    sapply(sum, simplify = FALSE)  %>% 
    as.tibble()

  names(rdf) <- named_cols 
  
  plot <- rdf %>%
    gather(
      desc_col, \total\, 1:ncol(.)
    ) %>% 
    ggplot(
      aes(
        x = if (invert.axis) total else reorder(desc_col, -total),
        y = if (invert.axis) reorder(desc_col, total) else total,
        fill = desc_col
      )
    ) +
    geom_col(
      width = col.width,
      position = position_dodge(dodge.width)
    )
  
  if (invert.axis) {
    plot <- plot +
      geom_label(
        aes(
          x = total,
          label = total,
        ),
        show.legend = show.legend
      )  
  } else {
    plot <- plot +
      geom_label(
        aes(
          y = total,
          label = total,
        ),
        show.legend = show.legend
      )
  }
  
  plot +
    labs(
        title = title,
        x = xlabel,
        y = ylabel
    ) +
    theme_classic() +
    theme(
      legend.position = legend.position,
      axis.title.x = if (!hide.xaxis.title) element_text(size=xaxis.title.size, vjust=xaxis.title.vjust)  else element_blank(),
      axis.title.y = if (!hide.yaxis.title) element_text(size=yaxis.title.size, vjust=yaxis.title.vjust) else element_blank(),
      axis.text.x = element_text(angle = xaxis.text.angle, vjust=xaxis.text.vjust)
    )
}

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->

join_columns_and_plot <- function(dfp, cols) {
   dfp %>% 
    select(cols) %>% 
    rowwise() %>% 
    sapply(as.numeric) %>% 
    as.tibble() %>% 
    rowwise() %>% 
    replace(is.na(.), 0) %>% 
    rowwise() %>% 
    sapply(sum, simplify = FALSE)  %>% 
    as.tibble()
}

Principais motivos para baixar apps


q7_names <-c("Feeling Depressed", "Need to carry out a task", "Feeling bored", "Want to be entertained", "Need to know something", "Other")

q7_cols <- names(df)[(21:26)]

df %>% 
  arrange_and_plot(
    q7_cols,
    q7_names,
    title = 'Fatores motivadores que levam as pessoas a baixarem apps',
    xlabel = 'Motivo',
    ylabel = 'Total',
    dodge.width = 0.5,
    col.width = 0.6,
    xaxis.title.vjust = -0.5
    )
Warning: `as.tibble()` was deprecated in tibble 2.0.0.
Please use `as_tibble()` instead.
The signature and semantics have changed, see `?as_tibble`.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(cols)` instead of `cols` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.

Principais formas de encontrar aplicativos

q8_cols = names(df)[(27:35)]

q8_names <- c(
  "Compare several to choose one",
  "Download the first presented",
  "Featured apps",
  "Among top downloads",
  "Randomly choose one that might interest",
  "Search using keywords",
  "Visit websites that review apps",
  "Use search engines",
  "Other"
)

df %>% 
   arrange_and_plot(
    q8_cols,
    q8_names,
    title = 'Fatores motivadores que levam as pessoas a baixarem apps',
    xlabel = 'Total',
    ylabel = 'Motivo',
    dodge.width = 0.5,
    col.width = 0.6,
    invert.axis = TRUE
    )

NA

O que mais consideram para baixar


q9_cols <- names(df)[(36:48)]

q9_names <- c(
  "Reviews by other users",
  "Name of app (e.g., catchy name)",
  "Number of users who have downloaded the app",
  "Icon (e.g., if the icon is attractive)",
  "Description of the app",
  "Features",
  "Number of users who have rated the app",
  "Price",
  "Star rating",
  "Size of app",
  "Screen shots (e.g., see how it looks running)",
  "Who developed the app",
  "Other"
)


df %>% 
  arrange_and_plot(
    q9_cols,
    q9_names,
    "Motivo",
    title = "Motivos para escolher o aplicativo para baixar",
    xlabel = "Total",
    ylabel = "Porque baixa",
    col.width = 0.7,
    invert.axis = TRUE,
    hide.yaxis.title = TRUE,
    hide.xaxis.title = TRUE
  )

Porque de fato baixam um aplicativo


q10_cols <- names(df)[(49:(49+14))]

q10_names <- c(
  "To interact with friends and/or family.",
  "To interact with people I don't know.",
  "To help me carry out a task.",
  "It is featured in the app store.",   
  "It is on the top downloads chart.",
  "It is advertised in the apps that I am using. ",
  "For entertainment.",
  "Out of curiosity. ",
  "An impulsive purchase.", 
  "It features brands or celebrities that\nI like\n(e.g., Coca-Cola, Michael Jackson). ",
  "It was mentioned in the media\n(e.g., TV, newspaper, radio, blogs). ",
  "It is an extension of the \nwebsite that I use (e.g., Facebook app). ",
  "It is recommended by friends and/or family. ",
  "For someone else (e.g., children, partner).",
  "Other"
)

df %>% 
  arrange_and_plot(
    q10_cols,
    q10_names,
    "Motivo",
    title = "Motivos que levam ao download do app",
    xlabel = "Total",
    ylabel = "",
    col.width = 0.6,
    dodge.width = 1,
    invert.axis = TRUE,
    hide.yaxis.title = TRUE,
    hide.xaxis.title = TRUE
  )

q9_cols <- names(df)[(64:(63+12))]

df %>% 
  arrange_and_plot(
    q9_cols,
    q9_cols,
    invert.axis = TRUE
  )


countries = c(
  "American",
  "Australian",
  "Brazilian",
  "British",
  "Canadian",
  "Chinese",
  "French",
  "German",
  "Indian",
  "Italian",
  "Japanese",
  "Mexican",
  "Russian",
  "South Korean",
  "Spanish",
  "Other",
  "Not assigned - NA"
)

country_df <- df %>% 
  group_by(Q19) %>% 
  count() %>% 
  dplyr::mutate(
    Q19 = as.numeric(Q19)
  ) %>%
  dplyr::arrange(Q19) %>% 
  mutate(
    Q19 = as.character(Q19)
  )


country_df$Q19 <- countries


country_df %>% 
  ggplot(
    aes(
      y = reorder(Q19, n),
      x = n,
      fill = Q19
    )
  ) +
  geom_bar(
    stat = "identity",
    position = position_dodge(10)
  ) +
  labs(
    x = 'Total de pessoas',
    y = 'País',
    fill = ''
  ) +
  theme(
    legend.position = "none",
    axis.text.x = element_text(vjust=0.5, angle = 15)
  )

df %>% 
  select(names(df)[c(76:79)]) %>% 
  drop_na
logit_user_feats <- c("Q5", "Q6", "Q16", "Q17", "Q18", "Q19", "Q23", "Q24", "Q26", "Q27")

df_logit <- df %>% 
  pivot_longer(starts_with("Q11_"), names_to="Potential", values_to="Potential_value") %>% 
  mutate(
    Potential = as.factor(as.numeric(str_extract(Potential, "([0-9]+)$"))),
    Q17 = as.integer(Q17)
  ) %>% 
  drop_na("Potential_value") %>% 
  select(
    logit_user_feats, starts_with("Q7_"), starts_with("Q8_"), 
    starts_with("Q9_"), starts_with("Q10_"), starts_with("Q11_"), 
    starts_with("Q13_"), starts_with("Q14_"), starts_with("Q15_"),
    Potential
  ) %>% 
  mutate_all(
    funs(as.numeric(.))
  ) %>% 
  mutate_all(
    funs(replace_na(., 0))
  ) %>% 
  mutate(
    Potential = as.factor(Potential)
  )

df_logit <- df %>% 
  pivot_longer(starts_with("Q11_"), names_to="Potential", values_to="Potential_value") %>% 
  mutate(
    Potential = as.factor(as.numeric(str_extract(Potential, "([0-9]+)$"))),
    Q17 = as.integer(Q17)
  ) %>% 
  drop_na("Potential_value") %>% 
  select(
    logit_user_feats, starts_with("Q7_"), starts_with("Q8_"), 
    starts_with("Q9_"), starts_with("Q10_"), starts_with("Q11_"), 
    starts_with("Q13_"), starts_with("Q14_"), starts_with("Q15_"),
    Potential
  ) %>% 
  mutate_all(
    funs(as.numeric(.))
  ) %>% 
  mutate_all(
    funs(replace_na(., 0))
  ) %>% 
  mutate(
    Potential = as.factor(Potential)
  )
df %>% 
  drop_na(Q17) %>% 
  group_by(Q17) %>% 
  count() %>% 
  arrange(desc(n))
df_logit %>% 
  select(Potential) %>% 
  group_by(Potential) %>% 
  count() %>% 
  arrange(n)
NA

Logit

Treinando o modelo

logit_fit
Call:
nnet::multinom(formula = Potential ~ ., data = train, family = "binomial", 
    MaxNWts = 10000)

Coefficients:
   (Intercept)          Q5           Q6        Q16          Q17        Q18          Q19
2    -2.831077  0.19314421  0.004161363 -0.3357207 -0.009387795 0.26225274 -0.007136793
3    -2.516666  0.14964958  0.062203240 -0.4114570  0.004371494 0.06412545 -0.043747198
4    -1.643322  0.02473883  0.038363577 -0.3069615  0.002536063 0.13703026 -0.017205541
5    -2.277490  0.13373126  0.050118183 -0.2801466 -0.005069066 0.15275730  0.003345424
6    -1.603665  0.05867205 -0.027128103 -0.2174974 -0.011237502 0.05232554 -0.024047783
7    -1.995366  0.12635273  0.064530462 -0.1977068 -0.008755982 0.21198390 -0.020068860
8    -2.841578  0.09212726  0.084028442 -0.5093149 -0.007700749 0.22589499 -0.038007138
9    -2.676805  0.14611839  0.083300078 -0.2886305 -0.008733964 0.18167614 -0.028369655
10   -2.139975 -0.05098983 -0.426191281 -0.1625053  0.010872033 0.02276676 -0.035750468
11   -2.506288  0.21970822  0.020871833 -0.4863416 -0.014578997 0.26021978 -0.008588354
           Q23          Q24          Q26          Q27       Q7_1         Q7_2        Q7_3
2  -0.11475293 -0.011932040 -0.017762590  0.001224567 -0.3273897 -0.006565511 -0.12778748
3  -0.07388938  0.029846580 -0.070107874 -0.018509979 -0.1886862 -0.069507829  0.03635108
4   0.07250743 -0.023823120 -0.056606214 -0.014272725 -0.2970201  0.033226531 -0.24981206
5   0.05211095 -0.018508863 -0.004296008 -0.015381987 -0.2153086  0.005961373 -0.25281799
6   0.10221845 -0.015402683 -0.018769485 -0.021353499 -0.2226241  0.099047243 -0.02343900
7  -0.00587136 -0.003947630 -0.082206616 -0.021578089 -0.5231015  0.078552878 -0.17132130
8   0.21164926 -0.016366188 -0.068373565 -0.016606348  0.1757757 -0.142145512 -0.26783935
9   0.12220663 -0.027326144 -0.061018920 -0.015603917 -0.4257900  0.278902985 -0.20898424
10  0.01902384 -0.009246391 -0.012659432 -0.024073792 -1.4169030 -0.576445905 -0.62210996
11  0.11007697 -0.015533882 -0.075624455  0.004333665 -0.1266129 -0.062915609 -0.12461105
          Q7_4        Q7_5        Q7_6      Q8_1         Q8_2        Q8_3        Q8_4
2   0.07402743 -0.04926993  0.42389213 0.4546129  0.054833705  0.25633159  0.18109714
3  -0.02432760 -0.09508477  0.41086061 0.2739049 -0.018247110  0.19367040  0.18530447
4   0.10814208  0.04369644  0.38750228 0.1739729  0.235013824  0.39712599 -0.03026940
5   0.16844707  0.15029793 -0.22545247 0.3261790  0.084001712  0.18183069  0.08173635
6  -0.05931305  0.08812191  0.17429044 0.2996749 -0.190020827  0.12068714  0.17854717
7   0.20030625 -0.04474142  0.18000242 0.2624625 -0.077350666  0.21700502  0.14269081
8  -0.53531851 -0.07689812 -0.91673528 0.4044391  0.237044845  0.09141466  0.23006722
9   0.01582758  0.14088673  0.04411266 0.3744076 -0.178807358  0.41666936  0.14154636
10 -0.31341224 -0.13515732  0.37093932 0.4664463  0.691994620 -0.19002242 -0.06748627
11  0.30474982  0.18214132 -0.80370520 0.2061919 -0.136897988  0.16972730  0.14954853
            Q8_5        Q8_7      Q8_8        Q8_9       Q8_10        Q9_1        Q9_2
2  -0.0927440011  0.22843554 0.6188075  0.28729806 -0.09479455 -0.17562083 -0.06637064
3   0.1180314934  0.20553981 0.3035256  0.26245845  0.20784151  0.04127033 -0.13585906
4  -0.1508795522  0.04273248 0.4728787  0.12342009 -0.55997498 -0.27201047  0.01691151
5  -0.0733877951  0.16236867 0.2946529  0.19563806  0.03857156  0.07773995 -0.14257689
6  -0.1803180913  0.10406247 0.2311458  0.05093760 -0.30938381  0.11858252 -0.17357420
7  -0.0005617848  0.06975359 0.4759930  0.22199743 -0.01609591 -0.05934720 -0.27227179
8   0.1126394863  0.16660657 0.8086141  0.46023488 -0.21607017 -0.19009589 -0.26620072
9  -0.2582946078  0.04400909 0.5689429 -0.01205932 -0.38115538 -0.08692433 -0.18962640
10  0.2978943298  0.22562167 0.1769604  0.42010753  0.92040894 -0.18067628  0.28628392
11 -0.1039243429 -0.03672964 0.5048358 -0.03904161 -0.78991114 -0.02439985 -0.20106557
           Q9_3        Q9_4        Q9_5        Q9_6         Q9_7       Q9_8        Q9_9
2   0.010794258  0.15501643 -0.01258929  0.01750330 -0.083674849 0.66093929  0.01879016
3  -0.005616802 -0.01413053  0.08863840  0.01071956 -0.081620317 0.92029361 -0.09614364
4   0.250670230 -0.10329657  0.02686441 -0.07008140 -0.050111043 0.16261538 -0.08588886
5   0.158764070  0.26121889  0.15058093  0.04660817 -0.058973640 0.30142604  0.00578427
6   0.072381441 -0.03027443  0.28362386  0.18080872 -0.125079342 0.59189995 -0.12307577
7   0.038574579  0.18874711  0.14475552  0.38167847 -0.018639986 0.26782217  0.09370258
8  -0.189706186  0.29495112 -0.02754503  0.13553867  0.109301344 0.35364094 -0.09946875
9   0.195708876  0.11186023  0.08867708  0.08432934 -0.007565676 0.25988088 -0.05095026
10 -0.341531332 -0.35313099  0.20057838 -0.08483723  0.068390101 0.08239902 -0.68873167
11  0.161127118  0.16666630  0.12963231  0.05253685  0.016356211 0.45419501 -0.18510437
         Q9_10         Q9_11      Q9_12      Q9_13       Q10_1       Q10_2       Q10_3
2   0.06941249  0.2838817087  0.4076446 -1.6125788  0.18849654  0.38378006  0.09888458
3  -0.01264827  0.1636982459  0.3256305 -2.9167772  0.10182969  0.02727020  0.20251712
4   0.15283003 -0.0510164725  0.2642467 -0.7174872  0.12072349  0.45336666  0.22499325
5   0.07090717  0.1030745363  0.1253765  0.2689275  0.16636850  0.19256866  0.33599264
6  -0.01924235  0.0880114819  0.2902647 -1.3245600  0.14196463  0.13784582  0.41006395
7  -0.01305607  0.1015923307  0.2415514 -1.0859023 -0.02410912  0.07253304  0.21761326
8  -0.08755311  0.0004197098  0.5042589 -2.4168312  0.33684650  0.26144058 -0.01639989
9   0.08039864  0.1327298874  0.2256257  0.2663563  0.04713361  0.33730367  0.22052983
10 -0.67898960  0.3334148956 -1.0354792  0.6090934  0.22271883 -0.74929341  0.17924710
11  0.06684000 -0.0216071559  0.5183782 -2.0375151  0.14507755  0.43563286  0.24543953
         Q10_4       Q10_5        Q10_6       Q10_7      Q10_8     Q10_9      Q10_10     Q10_11
2  -0.01824869  0.10215193  0.162355558 -0.33870546 -0.2435150 0.9041642  0.03481875 0.17984589
3   0.24460641 -0.03625905  0.080329952  0.16365242 -0.1236544 0.9157578  0.04951013 0.24666361
4   0.15931557 -0.10728450  0.308677295  0.05042364 -0.3388083 0.6370137  0.37231696 0.29242588
5   0.10859082  0.06250834  0.193782955 -0.14071722 -0.2186133 0.8479041  0.04337904 0.09852663
6   0.26849668 -0.05349044  0.170773541 -0.01561051 -0.1483034 0.8704540 -0.04689152 0.12906971
7   0.20008255 -0.06543156  0.263411862 -0.16118019 -0.1445994 1.0195425  0.34318033 0.18168666
8   0.24475656  0.11643685 -0.003948784 -0.14975360 -0.1224306 0.8263344  0.44298220 0.20467052
9   0.39733921  0.10852853  0.272558620  0.05258584 -0.2994447 1.0068521  0.13137397 0.04130151
10  0.31338940 -0.76191371 -0.819047089  0.02146000  0.4696538 1.1814127 -0.39299128 0.57138472
11  0.14090285  0.05401613  0.157245222 -0.01455343 -0.2273161 0.8907470  0.19554274 0.20504680
        Q10_12      Q10_13      Q10_14      Q10_15      Q13_1       Q13_2        Q13_3
2   0.22650233  0.01253063  0.10675680 -0.69091773 -0.8067342 -0.63669450  0.057701261
3   0.02549043  0.15536189  0.04250272  0.51432525 -0.8924092 -0.26751989  0.062381803
4   0.12342114 -0.03259669  0.10735930 -0.82617839 -1.1075524 -0.23291396  0.277940534
5   0.17346289  0.14596063  0.12767655 -0.74173957 -0.7299857  0.02392404  0.120803486
6   0.17728992 -0.05290743  0.25601113 -1.56052923 -0.3578338 -0.12878161  0.285393923
7   0.13232849  0.09257728 -0.10785407 -2.08681825 -0.6314696 -0.02376094  0.101484270
8   0.33601827  0.47444825 -0.13937788 -2.73883541 -0.9520312  0.04001074  0.242747669
9   0.11934481  0.19800758  0.06571727 -0.05160603 -0.7877894 -0.09882180  0.006756926
10 -0.37719835 -0.12026632 -1.26232357  3.09416727 -0.9221408 -0.75894517 -1.246875591
11 -0.03779334  0.16771581 -0.12082981  0.12441657 -0.7970070  0.03673945  0.206048689
         Q13_4       Q13_5       Q13_6        Q13_7       Q14_1      Q14_2       Q14_3
2   0.02447495  0.41085965  0.01236241  0.216524234 -0.42339013 0.16687301  0.64047720
3  -0.09410995 -0.01490311  0.10327466 -0.405644290 -0.21720073 0.01196077  0.26645161
4  -0.21049144  0.05630345  0.19512296 -0.251444538 -0.18012077 0.20326034  0.43899264
5   0.05424756  0.13820074  0.22268393  0.123192510 -0.12463029 0.12346176  0.13101793
6  -0.01863604  0.02155430  0.08190169  0.563211705 -0.04024215 0.17348826  0.22944540
7  -0.19918635 -0.08157111  0.04227276 -0.365884642 -0.26828743 0.22196887  0.32539145
8  -0.28864745  0.22403966 -0.17446306  0.178967532 -0.45251514 0.33066588  0.23462200
9  -0.10832183  0.07317816  0.09625005  1.911494063 -0.19144835 0.20568804  0.21634041
10 -0.12054782  0.12827956 -0.72118470  0.898523803 -0.56958297 0.89333305 -0.21785836
11 -0.12203964  0.09006985 -0.11722242  0.005613312 -0.16816271 0.09377080  0.02509614
         Q14_4       Q14_5       Q14_6       Q14_7       Q14_8        Q14_9       Q14_10
2   0.07140485 -0.26567013 -0.25129490  0.30203243 -0.42751502  0.045219330 -0.011489388
3  -0.01518089  0.14005862  0.08127085  0.34339798 -0.47022875 -0.035324252 -0.002281833
4   0.02193581  0.09384575  0.13019480  0.02192473 -0.46624910  0.210361040  0.027846321
5  -0.04802637 -0.26022717  0.18958431  0.06085254 -0.19555087 -0.032012518 -0.014500094
6  -0.02086528 -0.38317048  0.07713133  0.09796064 -0.31268075  0.222255862  0.059880137
7  -0.10508543  0.01409683 -0.14651419  0.05481870 -0.35642590  0.022960793 -0.089668210
8  -0.08840425  0.11196218 -0.14691357  0.13599169 -0.50426472  0.276170256 -0.085434843
9   0.09277991 -0.13973942 -0.26492603  0.05665647 -0.23859828  0.249661073 -0.055284070
10 -0.06952550  0.13085555 -0.03925273  0.47919262  0.02120778 -0.005914517  0.020280392
11  0.17193083  0.02754811 -0.16745450  0.01038164 -0.33134883 -0.161581020 -0.098744432
         Q14_11       Q14_12       Q14_13      Q14_15      Q14_14       Q15_1       Q15_2
2  -0.229503180  0.262958528 -0.088168418 -0.18357401  0.36375534  0.05810586 -0.09733213
3  -0.001239108 -0.075826309 -0.112957114 -0.37397575 -1.31930510  0.14091441 -0.03081196
4  -0.315487224 -0.007346129  0.222386225 -0.28383966 -1.21942287  0.05122575 -0.06325836
5   0.066230837 -0.059986489  0.005158116 -0.42832907 -0.42928068  0.13615237  0.22059837
6  -0.095986255 -0.180277655  0.170708408 -0.17453253  0.08275291  0.13943228  0.04579892
7   0.076512557  0.052639798 -0.006889711 -0.34412733  0.13282396 -0.11720144  0.14338829
8  -0.469625879 -0.041115423 -0.233210269 -0.16128050 -0.25252432 -0.21576047  0.27073734
9  -0.195739508 -0.006969107  0.002077257 -0.30650357  0.01097325 -0.06273817  0.19679786
10  0.116274467  0.349799506 -0.024606874 -0.38092847  0.29626501  0.21029537  0.18387818
11 -0.177963413 -0.284788502 -0.045453081 -0.09792457 -0.50663398  0.20842377  0.03821965
         Q15_3      Q15_4     Q15_5       Q15_6       Q15_7       Q15_8       Q15_9      Q15_10
2  -0.40488343 0.34428650 0.4891544 -0.14251733  0.38386558 -0.18224086 -0.11912023 -0.09996463
3  -0.13608256 0.08706679 0.1061022  0.17730599  0.05108660 -0.10473172 -0.09425231  0.09431644
4   0.14950542 0.33989602 0.1830148  0.10328183  0.03640673  0.10349762 -0.08827289  0.26166627
5  -0.42961260 0.18572163 0.2393143 -0.08936696 -0.11378233  0.01055479 -0.03109619 -0.02824228
6  -0.08582446 0.08831954 0.3321812 -0.04410963  0.06720909 -0.08996181 -0.21562052  0.07080580
7  -0.20082430 0.18746675 0.3303431  0.10924398 -0.02852805 -0.14390277  0.06653401  0.18871334
8  -0.12530735 0.70345397 0.3166134  0.13840664  0.02992726 -0.26204245  0.23936382  0.07050664
9  -0.40551026 0.27086580 0.1275485  0.05598596 -0.02439782 -0.14804981 -0.09801881  0.11010110
10 -0.57682101 0.09470300 0.1651234  0.39384591  0.23589631 -0.71144656 -0.25760026 -0.32517041
11 -0.07959043 0.32230413 0.1483324 -0.13773477  0.04503476  0.12662749  0.32575176  0.03236908
        Q15_11      Q15_12        Q15_13     Q15_14      Q15_15      Q15_16      Q15_17
2   0.16032766  0.03665671 -1.403467e-02 -0.3886217  0.01779135 -0.21293620  0.22096561
3   0.26226532  0.16004692  4.121008e-02 -0.4067031  0.01711580  0.06409822  0.04549150
4   0.38574035 -0.28937310 -2.393017e-02 -0.2601586 -0.21436901 -0.22503506  0.23383482
5   0.18580903  0.03083824  9.703141e-02 -0.4467016  0.10191144 -0.16475444  0.09935191
6   0.05875572 -0.05034018 -8.837030e-02 -0.3885621 -0.18442755 -0.12654367  0.34786799
7   0.22865406 -0.03515164  4.344807e-02 -0.2866016 -0.13753391 -0.07210316  0.10080014
8   0.27140979  0.10749261 -1.175003e-01 -0.2946104 -0.11991293 -0.28494410 -0.11678627
9   0.29777150 -0.10590795  3.983593e-05 -0.2911798  0.06847877  0.11152112  0.17092460
10 -0.75558885 -0.03411834  5.158809e-01 -0.5950110  0.23862376 -0.12471037  0.68524004
11  0.42323762 -0.24392313 -9.101441e-02 -0.4035014  0.12010785 -0.08984163  0.10878433
        Q15_18      Q15_19       Q15_20      Q15_21       Q15_22     Q15_23
2  -0.31330692  0.01240573 -0.003992033  0.45381678  0.013077043 -1.9702690
3  -0.27774286 -0.11811972 -0.010654094  0.07298789  0.019539959 -0.1057625
4  -0.11021496 -0.22199759 -0.143727902 -0.02325880  0.094172456 -0.5613058
5  -0.26980062 -0.05021865 -0.076960114 -0.18655709 -0.062958614  0.1491968
6   0.13678916 -0.08966400 -0.035833686  0.14855685  0.030043329 -5.5666995
7  -0.10368830  0.04608581  0.022320927  0.06391885 -0.009857221  0.2192474
8   0.09517296 -0.15855948  0.022567302 -0.33017371  0.164728979 -0.4915665
9   0.02824367 -0.18306298  0.022958288  0.02514391  0.263908911 -1.8954204
10  0.04876036 -0.21687427 -0.042411349  0.62679404 -0.081083855 -0.7456743
11 -0.21195829 -0.29953099 -0.215043711  0.00739897  0.118867569  1.0260196
 [ reached getOption("max.print") -- omitted 1 row ]

Residual Deviance: 30507.05 
AIC: 32685.05 

Avaliando o modelo


ytest <- test %>% 
  select(Potential)


MLmetrics::Accuracy(ypred, ytest$Potential)
[1] 0.2975238

Se fossemos chutar uma classe dentre as 12 possíveis, teríamos 1/12 em média de acertos. Isso é menor que a acurácia obtida, então no geral nosso modelo conseguiu aprender um pouco sobre os diferentes perfis.

pROC::roc(response = ytest$Potential, predictor=as.numeric(ypred)) %>% 
  plot
Warning in roc.default(response = ytest$Potential, predictor = as.numeric(ypred)) :
  'response' has more than two levels. Consider setting 'levels' explicitly or using 'multiclass.roc' instead
Setting levels: control = 1, case = 2
Setting direction: controls < cases

Clustering


df_km <- df_logit %>% 
  select(-Potential)
adjust_kmeans <- function(k) {
  k_fit <- df_knn %>% 
    kmeans(k, iter.max = 30)
  
  w <- k_fit$tot.withinss
  tibble(k = k, w = w)
}

k_adjust <- map_dfr(2:10, adjust_kmeans)
k_adjust %>% 
  ggplot(
    aes(
      x = k, 
      y = w
    )
  ) + 
  geom_line() +
  geom_point(colour = "red", size = 3) +
  theme_minimal(12)

Iremos separar em 5 grupos…


k_adj <- df_km %>% 
  kmeans(5, iter.max = 30)

length(k_adj$cluster)
[1] 10499
df_km$cluster = k_adj$cluster

Analisando grupos

Frequencia de uso

df_km %>% 
  select(Q5, cluster) %>% 
  drop_na() %>% 
  mutate(
    Q5 = q5_answers[Q5,],
    cluster = as.factor(cluster)
  ) %>% 
  group_by(Q5, cluster) %>% 
    count() %>% 
  arrange(desc(n)) %>% 
  ggplot(
    aes(
      x = reorder(Q5, -n),
      y = n,
      fill = cluster
    )
  ) +
  geom_bar(
    stat = "identity",
    position = "fill"
  ) +
  labs(
    y = 'Frequência de acesso à loja de aplicativos',
    x = 'Total'
  ) +
  theme(
    axis.text.x = element_text(angle = 20, vjust = 0.5),
  )

Conseguimos ver que 2 grupos parecem acessar mais a loja do que os demais…

Visualizaremos a correlação:

cor(df_km$Q5, df_km$cluster)
[1] -0.2072271

Quanto maior o uso, menor o cluster… é o que conseguimos ver também em nosso gráfico.

Prosseguiremos…

  df %>% 
    select(starts_with(col), cluster) %>% 
    pivot_longer(cols = starts_with(col), names_to = names_to, values_to = values_to)
Error in `select()`:
! `match` must be a character vector of non empty strings.
Backtrace:
  1. df %>% select(starts_with(col), cluster) %>% ...
 24. tidyselect::starts_with(col)
 25. tidyselect:::check_match(match)

O que motiva as pessoas de cada um dos grupos a procurar por aplicativo?

Os grupos parecem ter uma distribuição homogenea no que diz respeito as razões por baixas aplicativo.

O que as pessoas dos grupos consideram para baixar um aplicativo?

LS0tCnRpdGxlOiAiV29ybGR3aWRlIE1vYmlsZSBBcHAgVXNlciBCZWhhdmlvciBEYXRhc2V0IgphdXRob3I6ICJEaWVnbyIKZGF0ZTogIjIvMjIvMjAyMiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIGVjaG8gPSBGQUxTRSwgZWNobyA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBUUlVFLCBjb2xsYXBzZSA9IFRSVUUpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHN0cmluZ3IpCmBgYAoKIyMgQ29udGV4dG8KCi4uLgoKIyMgQW7DoWxpc2UKCiMjIyBMZWl0dXJhIGRvIGNvbmp1bnRvIGRlIGRhZG9zCgpgYGB7cn0KZGYgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKCcuL21vYmlsZV9hcHBfdXNlcl9kYXRhc2V0XzEueGxzeCcpWy0xLF0KYGBgCgojIyMgRXhwbG9yYcOnw6NvCgo+IFVtYSB2ZXogcXVlIMOpIHVtYSBwZXNxdWlzYSBzb2JyZSAqbW9iaWxlIGRldmljZXMqLCB2ZXJlbW9zIHF1YWwgYSBwcm9wb3LDp8OjbyBkZSBwZXNzb2FzIHF1ZSBkZSBmYXRvIHBvc3N1ZW0gdW0gKmRldmljZSouCgpgYGB7cn0KCmRmICU+JSAKICBzZWxlY3QoUTIpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIG11dGF0ZSgKICAgIFEyID0gY2FzZV93aGVuKAogICAgICBRMiA9PSAxIH4gIlBvc3N1aSIsCiAgICAgIFEyICE9IDEgfiAiTsOjbyBQb3NzdWkiCiAgICApCiAgKSAlPiUgCiAgZ2dwbG90KAogICAgYWVzKAogICAgICB5ID0gUTIsCiAgICAgIGZpbGwgPSBRMgogICAgKQogICkgKwogIGdlb21fYmFyKAogICAgcG9zaXRpb24gPSAiZG9kZ2UiLAogICkgKwogIGdlb21fbGFiZWwoCiAgICAgIHN0YXQgPSAnY291bnQnLAogICAgICBhZXMoCiAgICAgICAgbGFiZWwgPSAuLmNvdW50Li4sCiAgICAgICksCiAgICAgIGNvbG9yID0gJ3doaXRlJywKICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKyAKICBsYWJzKAogICAgeSA9ICIiLAogICAgeCA9ICJUb3RhbCBkZSBQZXNzb2FzIiwKICAgIHRpdGxlID0gIkRpc3RyaWJ1acOnw6NvIGRlIHBlc3NvYXMgcXVlIHRlbSBvdSBuw6NvIGNlbHVsYXIiLAogICAgc3VidGl0bGUgPSAiRGFkb3Mgb3JpdW5kb3MgZGEgcGVzcXVpc2EgcmVhbGl6YWRhIHBlbGEgSGFydmFyZCIKICApICsKICBzY2FsZV9maWxsX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoICIjQzQxNjFDIiwgIiMwMDk0OTEiKSwKICApICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PS0uMiwgc2l6ZT0xMSksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkKICApIAoKYGBgCjxiciAvPgo8YnIgLz4KCj4gUG9kZW1vcyB2aXN1YWxpemFyIHF1ZSBhIGdyYW5kZSBwYXJ0ZSBkYXMgcGVzc29hcyBwb3NzdWVtIGNlbHVsYXIuCgo8YnIgLz4KCj4gQSBwcm9wb3LDp8OjbyBkZSBwZXNzb2FzIHF1ZSBuw6NvIHRlbSDDqSBkZSBgciBzY2FsZXM6OnBlcmNlbnQocm91bmQoMTIwOC8xMDIwMCwgMikpYC4KCjxiciAvPgoKPiBWaXN1YWxpemFyZW1vcyBhZ29yYSBvcyBkaWZlcmVudGVzIHRpcG9zIGRlIGRpc3Bvc2l0aXZvcyB1dGlsaXphZG9zIHBlbG9zIHVzdcOhcmlvcyBxdWUgcG9zc3VlbSBjZWx1bGFyIAo+IAoKCmBgYHtyfQoKcGhvbmVfZm9ybWF0IDwtIGZ1bmN0aW9uIChwaG9uZV9saXN0LCBwaG9uZV90eXBlLCBhcHBseV9mdW5jdGlvbiA9IGZ1bmN0aW9uKHBhcmFtKSBwYXJhbSkgewogIHBob25lX2RpYyA9IGxpc3QoCiAgICBhcHBsZSA9IGMoImFwcGxlIiwgImlwaG9uZSIsICJpcGFkIiwgImFwbGUiLCAiYXBwYWxlIiwgImlwb2QiLCAiYXBsbGUiLCAiaS1waG9uZSIsICJpcG9uZSIsICJhcHBsa2UiLCAiYXBwbHIiLCAiYXBwbWUiLCAiaXBob24iKSwKICAgIGJsYWNrYmVycnkgPSBjKCJibGFja2JlcnJ5IiwgImJsYWNrYiIsICJibGFja2ViIiwgImJhY2xrYmVycnkiLCAiYmxha2NrYmVycnkiLCAiYmxhY2JlcnJ5IiwgImJsYWtiZXJyeSIsICJibGFja2VycnkiLCAiYmxlY2tiZXJyeSIpLAogICAgc2Ftc3VuZyA9IGMoInNhbXN1bmciLCAic2Ftc3VtZyIsICJzYW5zdW5nIiwgInN1bXN1bmciLCAic2Ftc3VnIiwgInNhbXN1biIsICAic2FtZ3VuZyIsICJzYW1zaW5nIiwgInNhbXVuZyIsICJzYW5zdWciLCAic2FtYXN1bmciLCAic2Ftc2FuZyIsICJzYW1zb25nIiwgInN1bXNhbmciLCAiZ2FsYXh5bm90ZSIpLAogICAgbnVsbCA9IGMoIlxcPyIsICI5MDAwIiwgIjkzMHAiKSwKICAgIHNvbnlfZXJpY3Nzb24gPSBjKCJzb255LSIsICJzb255ZXIiLCAic29ueSIsICJlcmlzb24iKSwKICAgIG5va2lhID0gYygibm9raWEiLCAibm9reWEiKSwKICAgIGFzdXMgPSBjKCJhc3VzIiksCiAgICBhY2VyID0gYygiYWNlciIpCiAgKSAKICAKICAKICBzdHJfZGV0ZWN0KHBob25lX2xpc3QsIHBhc3RlKHBob25lX2RpY1tbcGhvbmVfdHlwZV1dLCBjb2xsYXBzZSA9ICJ8IikpIH4gYXBwbHlfZnVuY3Rpb24ocGhvbmVfdHlwZSkKfQoKcGhvbmVzIDwtIGRmICU+JQogIGZpbHRlcihRMiA9PSAxKSAlPiUgCiAgc2VsZWN0KFEzXzFfVEVYVCkgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgbXV0YXRlKAogICAgUTMgPSBzdHJfcmVwbGFjZShzdHJfdG9fbG93ZXIoUTNfMV9URVhUKSwgIiAiLCAiIikKICApICU+JSAKICBtdXRhdGUoCiAgICBRMyA9IGNhc2Vfd2hlbigKICAgICAgcGhvbmVfZm9ybWF0KFEzLCAiYXBwbGUiKSwKICAgICAgcGhvbmVfZm9ybWF0KFEzLCAic2Ftc3VuZyIpLAogICAgICBwaG9uZV9mb3JtYXQoUTMsICJibGFja2JlcnJ5IiksCiAgICAgIHBob25lX2Zvcm1hdChRMywgIm51bGwiKSwKICAgICAgcGhvbmVfZm9ybWF0KFEzLCAic29ueV9lcmljc3NvbiIsIGZ1bmN0aW9uKHBhcmFtKSBzdHJfcmVwbGFjZShwYXJhbSwgIl8iLCAiICIpKSwKICAgICAgVFJVRSB+IFEzCiAgICApCiAgKSAlPiUgCiAgZ3JvdXBfYnkoUTMpICU+JSAKICBjb3VudCgpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgCgpwaG9uZXMKYGBgCgpgYGB7cn0KbGVuZ3RoKG5hbWVzKGRmKSkKYGBgCgpgYGB7cn0KZGYKYGBgCgoKCmBgYHtyfQoKcTVfYW5zd2VycyA8LSBkYXRhLmZyYW1lKAogIHJvdy5uYW1lcyA9IGMoMSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSksCiAgdmFsID0gYygiTmV2ZXIiLCAiTGVzcyB0aGFuIG9uY2UgYSBtb250aCAiLCAiT25jZSBhIG1vbnRoIiwgIk1vcmUgdGhhbiBvbmNlIGEgbW9udGgiLCAiT25jZSBhIHdlZWsiLCAiTW9yZSB0aGFuIG9uY2UgYSB3ZWVrIiwgIk9uY2UgYSBkYXkiLCAiU2V2ZXJhbCB0aW1lcyBhIGRheSIsICJPdGhlciIpCikKCmRmICU+JSAKICBzZWxlY3QoUTUpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIG11dGF0ZSgKICAgIFE1X1RFWFQgPSBxcl9hbnN3ZXJzW1E1LCBdCiAgKSAlPiUgCiAgZ3JvdXBfYnkoUTVfVEVYVCkgJT4lIAogIGNvdW50KCkgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkgJT4lIAogIGdncGxvdCgKICAgIGFlcygKICAgICAgeCA9IHJlb3JkZXIoUTVfVEVYVCwgLW4pLAogICAgICB5ID0gbiwKICAgICAgZmlsbCA9IFE1X1RFWFQKICAgICkKICApICsKICBnZW9tX2NvbCgpICsKICBsYWJzKAogICAgeCA9ICdGcmVxdWVuY2lhIGRlIGFiZXJ0dXJhIGRhIGxvamEgZGUgYXBsaWNhdGl2b3MnLAogICAgeSA9ICdUb3RhbCcsCiAgICBmaWxsID0gIkZyZXF1w6puY2lhIgogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3Q9LjYpLAogICkKICAKYGBgCgoKYGBge3J9CgpxNl9hbnN3ZXJzIDwtIGRhdGEuZnJhbWUoCiAgcm93Lm5hbWVzID0gYygxLCAyLCAzLCA0LCA1LCA2KSwKICB2YWwgPSBjKCIwIC0gMSIsICIyIC0gNSIsICI2IC0gMTAiLCAiMTEgLSAyMCIsICIyMSAtIDMwIiwgIk1haXMgZGUgMzAiKQopCgoKZGYgJT4lIAogIHNlbGVjdChRNikgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgbXV0YXRlKAogICAgUTZfVEVYVCA9IHE2X2Fuc3dlcnNbUTYsXQogICkgJT4lIAogIGdyb3VwX2J5KFE2X1RFWFQpICU+JSAKICBjb3VudCgpICU+JSAKICBnZ3Bsb3QoCiAgICBhZXMoCiAgICAgIHggPSByZW9yZGVyKFE2X1RFWFQsIC1uKSwKICAgICAgeSA9IG4sCiAgICAgIGZpbGwgPSBRNl9URVhUCiAgICApCiAgKSArCiAgZ2VvbV9jb2woKSArCiAgbGFicygKICAgIHggPSAnUXVhbnRpZGFkZSBkZSBhcGxpY2F0aXZvcyBiYWl4YWRvcyBwb3IgbcOqcycsCiAgICB5ID0gJ1RvdGFsJywKICApICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoCiAgICBmaWxsID0gJ0ZyZXF1w6puY2lhJwogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMSksCiAgKQoKYGBgCgpWYW1vcyB2ZXIgc2UgYSBnYWxlcmEgcXVlIG1haXMgYmFpeGEgw6kgYSBnYWxlcmEgcXVlIG1haXMgYWNlc3NhIGEgbG9qYQoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMH0KCmRmICU+JSAKICBzZWxlY3QoUTUsIFE2KSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBtdXRhdGUoCiAgICBRNSA9IHE1X2Fuc3dlcnNbUTUsXSwKICAgIFE2ID0gcTZfYW5zd2Vyc1tRNiwgXQogICkgJT4lIAogIGdyb3VwX2J5KFE1LCBRNikgJT4lIAogICAgY291bnQoKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUgCiAgZ2dwbG90KAogICAgYWVzKAogICAgICB5ID0gcmVvcmRlcihRNSwgLW4pLAogICAgICB4ID0gbiwKICAgICAgZmlsbCA9IFE2CiAgICApCiAgKSArCiAgZ2VvbV9iYXIoCiAgICBzdGF0ID0gImlkZW50aXR5IiwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKQogICkgKwogIGdlb21fbGFiZWwoCiAgICBhZXMoCiAgICAgIGxhYmVsID0gbiwKICAgICksCiAgICBzaXplID0gMwogICkgKwogIGxhYnMoCiAgICB5ID0gJ0ZyZXF1w6puY2lhIGRlIGFjZXNzbyDDoCBsb2phIGRlIGFwbGljYXRpdm9zJywKICAgIHggPSAnVG90YWwnCiAgKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIwLCB2anVzdCA9IDAuNSksCiAgKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gJ1E2JykKCmBgYAoKIyMjIyBEZWZpbmluZG8gZnVuw6fDo28gZ2Vuw6lyaWNhcyBwYXJhIGNvbnRhZ2VtIGUgcGxvdGFnZW0gZGUgZHVtbXkgdmFycwoKYGBge3J9CmFycmFuZ2VfYW5kX3Bsb3QgPC0gZnVuY3Rpb24oZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVkX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY19jb2wgPSAicmVhc29uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYmVsID0gIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYmVsID0gIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wud2lkdGggPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9kZ2Uud2lkdGggPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXMudGl0bGUuc2l6ZSA9IDEzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzLnRpdGxlLnZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzLnRpdGxlLnNpemUgPSAxMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcy50aXRsZS52anVzdCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXMudGV4dC5hbmdsZSA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXMudGV4dC52anVzdCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW52ZXJ0LmF4aXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWRlLnlheGlzLnRpdGxlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlkZS54YXhpcy50aXRsZSA9IEZBTFNFCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7CiAgcmRmIDwtIGRmICU+JSAKICAgIHNlbGVjdChjb2xzKSAlPiUgCiAgICByb3d3aXNlKCkgJT4lIAogICAgc2FwcGx5KGFzLm51bWVyaWMpICU+JSAKICAgIGFzLnRpYmJsZSgpICU+JSAKICAgIHJvd3dpc2UoKSAlPiUgCiAgICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUgCiAgICByb3d3aXNlKCkgJT4lIAogICAgc2FwcGx5KHN1bSwgc2ltcGxpZnkgPSBGQUxTRSkgICU+JSAKICAgIGFzLnRpYmJsZSgpCgogIG5hbWVzKHJkZikgPC0gbmFtZWRfY29scyAKICAKICBwbG90IDwtIHJkZiAlPiUKICAgIGdhdGhlcigKICAgICAgZGVzY19jb2wsICJ0b3RhbCIsIDE6bmNvbCguKQogICAgKSAlPiUgCiAgICBnZ3Bsb3QoCiAgICAgIGFlcygKICAgICAgICB4ID0gaWYgKGludmVydC5heGlzKSB0b3RhbCBlbHNlIHJlb3JkZXIoZGVzY19jb2wsIC10b3RhbCksCiAgICAgICAgeSA9IGlmIChpbnZlcnQuYXhpcykgcmVvcmRlcihkZXNjX2NvbCwgdG90YWwpIGVsc2UgdG90YWwsCiAgICAgICAgZmlsbCA9IGRlc2NfY29sCiAgICAgICkKICAgICkgKwogICAgZ2VvbV9jb2woCiAgICAgIHdpZHRoID0gY29sLndpZHRoLAogICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKGRvZGdlLndpZHRoKQogICAgKQogIAogIGlmIChpbnZlcnQuYXhpcykgewogICAgcGxvdCA8LSBwbG90ICsKICAgICAgZ2VvbV9sYWJlbCgKICAgICAgICBhZXMoCiAgICAgICAgICB4ID0gdG90YWwsCiAgICAgICAgICBsYWJlbCA9IHRvdGFsLAogICAgICAgICksCiAgICAgICAgc2hvdy5sZWdlbmQgPSBzaG93LmxlZ2VuZAogICAgICApICAKICB9IGVsc2UgewogICAgcGxvdCA8LSBwbG90ICsKICAgICAgZ2VvbV9sYWJlbCgKICAgICAgICBhZXMoCiAgICAgICAgICB5ID0gdG90YWwsCiAgICAgICAgICBsYWJlbCA9IHRvdGFsLAogICAgICAgICksCiAgICAgICAgc2hvdy5sZWdlbmQgPSBzaG93LmxlZ2VuZAogICAgICApCiAgfQogIAogIHBsb3QgKwogICAgbGFicygKICAgICAgICB0aXRsZSA9IHRpdGxlLAogICAgICAgIHggPSB4bGFiZWwsCiAgICAgICAgeSA9IHlsYWJlbAogICAgKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUoCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGxlZ2VuZC5wb3NpdGlvbiwKICAgICAgYXhpcy50aXRsZS54ID0gaWYgKCFoaWRlLnhheGlzLnRpdGxlKSBlbGVtZW50X3RleHQoc2l6ZT14YXhpcy50aXRsZS5zaXplLCB2anVzdD14YXhpcy50aXRsZS52anVzdCkgIGVsc2UgZWxlbWVudF9ibGFuaygpLAogICAgICBheGlzLnRpdGxlLnkgPSBpZiAoIWhpZGUueWF4aXMudGl0bGUpIGVsZW1lbnRfdGV4dChzaXplPXlheGlzLnRpdGxlLnNpemUsIHZqdXN0PXlheGlzLnRpdGxlLnZqdXN0KSBlbHNlIGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSB4YXhpcy50ZXh0LmFuZ2xlLCB2anVzdD14YXhpcy50ZXh0LnZqdXN0KQogICAgKQp9CgoKam9pbl9jb2x1bW5zX2FuZF9wbG90IDwtIGZ1bmN0aW9uKGRmcCwgY29scykgewogICBkZnAgJT4lIAogICAgc2VsZWN0KGNvbHMpICU+JSAKICAgIHJvd3dpc2UoKSAlPiUgCiAgICBzYXBwbHkoYXMubnVtZXJpYykgJT4lIAogICAgYXMudGliYmxlKCkgJT4lIAogICAgcm93d2lzZSgpICU+JSAKICAgIHJlcGxhY2UoaXMubmEoLiksIDApICU+JSAKICAgIHJvd3dpc2UoKSAlPiUgCiAgICBzYXBwbHkoc3VtLCBzaW1wbGlmeSA9IEZBTFNFKSAgJT4lIAogICAgYXMudGliYmxlKCkKfQoKYGBgCgoKIyMjIyBQcmluY2lwYWlzIG1vdGl2b3MgcGFyYSBiYWl4YXIgYXBwcyAKCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD00fQoKcTdfbmFtZXMgPC1jKCJGZWVsaW5nIERlcHJlc3NlZCIsICJOZWVkIHRvIGNhcnJ5IG91dCBhIHRhc2siLCAiRmVlbGluZyBib3JlZCIsICJXYW50IHRvIGJlIGVudGVydGFpbmVkIiwgIk5lZWQgdG8ga25vdyBzb21ldGhpbmciLCAiT3RoZXIiKQoKcTdfY29scyA8LSBuYW1lcyhkZilbKDIxOjI2KV0KCmRmICU+JSAKICBhcnJhbmdlX2FuZF9wbG90KAogICAgcTdfY29scywKICAgIHE3X25hbWVzLAogICAgdGl0bGUgPSAnRmF0b3JlcyBtb3RpdmFkb3JlcyBxdWUgbGV2YW0gYXMgcGVzc29hcyBhIGJhaXhhcmVtIGFwcHMnLAogICAgeGxhYmVsID0gJ01vdGl2bycsCiAgICB5bGFiZWwgPSAnVG90YWwnLAogICAgZG9kZ2Uud2lkdGggPSAwLjUsCiAgICBjb2wud2lkdGggPSAwLjYsCiAgICB4YXhpcy50aXRsZS52anVzdCA9IC0wLjUKICAgICkKYGBgCgoKIyMjIyBQcmluY2lwYWlzIGZvcm1hcyBkZSBlbmNvbnRyYXIgYXBsaWNhdGl2b3MKCgpgYGB7ciwgZmlnLndpZHRoPTYsIGhlaWdodCA9IDZ9CnE4X2NvbHMgPSBuYW1lcyhkZilbKDI3OjM1KV0KCnE4X25hbWVzIDwtIGMoCiAgIkNvbXBhcmUgc2V2ZXJhbCB0byBjaG9vc2Ugb25lIiwKICAiRG93bmxvYWQgdGhlIGZpcnN0IHByZXNlbnRlZCIsCiAgIkZlYXR1cmVkIGFwcHMiLAogICJBbW9uZyB0b3AgZG93bmxvYWRzIiwKICAiUmFuZG9tbHkgY2hvb3NlIG9uZSB0aGF0IG1pZ2h0IGludGVyZXN0IiwKICAiU2VhcmNoIHVzaW5nIGtleXdvcmRzIiwKICAiVmlzaXQgd2Vic2l0ZXMgdGhhdCByZXZpZXcgYXBwcyIsCiAgIlVzZSBzZWFyY2ggZW5naW5lcyIsCiAgIk90aGVyIgopCgpkZiAlPiUgCiAgIGFycmFuZ2VfYW5kX3Bsb3QoCiAgICBxOF9jb2xzLAogICAgcThfbmFtZXMsCiAgICB0aXRsZSA9ICdGYXRvcmVzIG1vdGl2YWRvcmVzIHF1ZSBsZXZhbSBhcyBwZXNzb2FzIGEgYmFpeGFyZW0gYXBwcycsCiAgICB4bGFiZWwgPSAnVG90YWwnLAogICAgeWxhYmVsID0gJ01vdGl2bycsCiAgICBkb2RnZS53aWR0aCA9IDAuNSwKICAgIGNvbC53aWR0aCA9IDAuNiwKICAgIGludmVydC5heGlzID0gVFJVRQogICAgKQogIApgYGAKCiMjIyMgTyBxdWUgbWFpcyBjb25zaWRlcmFtIHBhcmEgYmFpeGFyCgpgYGB7ciwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTB9CgpxOV9jb2xzIDwtIG5hbWVzKGRmKVsoMzY6NDgpXQoKcTlfbmFtZXMgPC0gYygKICAiUmV2aWV3cyBieSBvdGhlciB1c2VycyIsCiAgIk5hbWUgb2YgYXBwIChlLmcuLCBjYXRjaHkgbmFtZSkiLAogICJOdW1iZXIgb2YgdXNlcnMgd2hvIGhhdmUgZG93bmxvYWRlZCB0aGUgYXBwIiwKICAiSWNvbiAoZS5nLiwgaWYgdGhlIGljb24gaXMgYXR0cmFjdGl2ZSkiLAogICJEZXNjcmlwdGlvbiBvZiB0aGUgYXBwIiwKICAiRmVhdHVyZXMiLAogICJOdW1iZXIgb2YgdXNlcnMgd2hvIGhhdmUgcmF0ZWQgdGhlIGFwcCIsCiAgIlByaWNlIiwKICAiU3RhciByYXRpbmciLAogICJTaXplIG9mIGFwcCIsCiAgIlNjcmVlbiBzaG90cyAoZS5nLiwgc2VlIGhvdyBpdCBsb29rcyBydW5uaW5nKSIsCiAgIldobyBkZXZlbG9wZWQgdGhlIGFwcCIsCiAgIk90aGVyIgopCgoKZGYgJT4lIAogIGFycmFuZ2VfYW5kX3Bsb3QoCiAgICBxOV9jb2xzLAogICAgcTlfbmFtZXMsCiAgICAiTW90aXZvIiwKICAgIHRpdGxlID0gIk1vdGl2b3MgcGFyYSBlc2NvbGhlciBvIGFwbGljYXRpdm8gcGFyYSBiYWl4YXIiLAogICAgeGxhYmVsID0gIlRvdGFsIiwKICAgIHlsYWJlbCA9ICJQb3JxdWUgYmFpeGEiLAogICAgY29sLndpZHRoID0gMC43LAogICAgaW52ZXJ0LmF4aXMgPSBUUlVFLAogICAgaGlkZS55YXhpcy50aXRsZSA9IFRSVUUsCiAgICBoaWRlLnhheGlzLnRpdGxlID0gVFJVRQogICkKYGBgCgojIyMjIFBvcnF1ZSBkZSBmYXRvIGJhaXhhbSB1bSBhcGxpY2F0aXZvCgpgYGB7cn0KCnExMF9jb2xzIDwtIG5hbWVzKGRmKVsoNDk6KDQ5KzE0KSldCgpxMTBfbmFtZXMgPC0gYygKICAiVG8gaW50ZXJhY3Qgd2l0aCBmcmllbmRzIGFuZC9vciBmYW1pbHkuIiwKICAiVG8gaW50ZXJhY3Qgd2l0aCBwZW9wbGUgSSBkb24ndCBrbm93LiIsCiAgIlRvIGhlbHAgbWUgY2Fycnkgb3V0IGEgdGFzay4iLAogICJJdCBpcyBmZWF0dXJlZCBpbiB0aGUgYXBwIHN0b3JlLiIsCQogICJJdCBpcyBvbiB0aGUgdG9wIGRvd25sb2FkcyBjaGFydC4iLAogICJJdCBpcyBhZHZlcnRpc2VkIGluIHRoZSBhcHBzIHRoYXQgSSBhbSB1c2luZy4gIiwKICAiRm9yIGVudGVydGFpbm1lbnQuIiwKICAiT3V0IG9mIGN1cmlvc2l0eS4gIiwKICAiQW4gaW1wdWxzaXZlIHB1cmNoYXNlLiIsIAogICJJdCBmZWF0dXJlcyBicmFuZHMgb3IgY2VsZWJyaXRpZXMgdGhhdFxuSSBsaWtlXG4oZS5nLiwgQ29jYS1Db2xhLCBNaWNoYWVsIEphY2tzb24pLiAiLAogICJJdCB3YXMgbWVudGlvbmVkIGluIHRoZSBtZWRpYVxuKGUuZy4sIFRWLCBuZXdzcGFwZXIsIHJhZGlvLCBibG9ncykuICIsCiAgIkl0IGlzIGFuIGV4dGVuc2lvbiBvZiB0aGUgXG53ZWJzaXRlIHRoYXQgSSB1c2UgKGUuZy4sIEZhY2Vib29rIGFwcCkuICIsCiAgIkl0IGlzIHJlY29tbWVuZGVkIGJ5IGZyaWVuZHMgYW5kL29yIGZhbWlseS4gIiwKICAiRm9yIHNvbWVvbmUgZWxzZSAoZS5nLiwgY2hpbGRyZW4sIHBhcnRuZXIpLiIsCiAgIk90aGVyIgopCgpkZiAlPiUgCiAgYXJyYW5nZV9hbmRfcGxvdCgKICAgIHExMF9jb2xzLAogICAgcTEwX25hbWVzLAogICAgIk1vdGl2byIsCiAgICB0aXRsZSA9ICJNb3Rpdm9zIHF1ZSBsZXZhbSBhbyBkb3dubG9hZCBkbyBhcHAiLAogICAgeGxhYmVsID0gIlRvdGFsIiwKICAgIHlsYWJlbCA9ICIiLAogICAgY29sLndpZHRoID0gMC42LAogICAgZG9kZ2Uud2lkdGggPSAxLAogICAgaW52ZXJ0LmF4aXMgPSBUUlVFLAogICAgaGlkZS55YXhpcy50aXRsZSA9IFRSVUUsCiAgICBoaWRlLnhheGlzLnRpdGxlID0gVFJVRQogICkKYGBgCgoKYGBge3J9CnE5X2NvbHMgPC0gbmFtZXMoZGYpWyg2NDooNjMrMTIpKV0KCmRmICU+JSAKICBhcnJhbmdlX2FuZF9wbG90KAogICAgcTlfY29scywKICAgIHE5X2NvbHMsCiAgICBpbnZlcnQuYXhpcyA9IFRSVUUKICApCgpgYGAKCgpgYGB7cn0KCmNvdW50cmllcyA9IGMoCiAgIkFtZXJpY2FuIiwKICAiQXVzdHJhbGlhbiIsCiAgIkJyYXppbGlhbiIsCiAgIkJyaXRpc2giLAogICJDYW5hZGlhbiIsCiAgIkNoaW5lc2UiLAogICJGcmVuY2giLAogICJHZXJtYW4iLAogICJJbmRpYW4iLAogICJJdGFsaWFuIiwKICAiSmFwYW5lc2UiLAogICJNZXhpY2FuIiwKICAiUnVzc2lhbiIsCiAgIlNvdXRoIEtvcmVhbiIsCiAgIlNwYW5pc2giLAogICJPdGhlciIsCiAgIk5vdCBhc3NpZ25lZCAtIE5BIgopCgpjb3VudHJ5X2RmIDwtIGRmICU+JSAKICBncm91cF9ieShRMTkpICU+JSAKICBjb3VudCgpICU+JSAKICBkcGx5cjo6bXV0YXRlKAogICAgUTE5ID0gYXMubnVtZXJpYyhRMTkpCiAgKSAlPiUKICBkcGx5cjo6YXJyYW5nZShRMTkpICU+JSAKICBtdXRhdGUoCiAgICBRMTkgPSBhcy5jaGFyYWN0ZXIoUTE5KQogICkKCgpjb3VudHJ5X2RmJFExOSA8LSBjb3VudHJpZXMKCgpjb3VudHJ5X2RmICU+JSAKICBnZ3Bsb3QoCiAgICBhZXMoCiAgICAgIHkgPSByZW9yZGVyKFExOSwgbiksCiAgICAgIHggPSBuLAogICAgICBmaWxsID0gUTE5CiAgICApCiAgKSArCiAgZ2VvbV9iYXIoCiAgICBzdGF0ID0gImlkZW50aXR5IiwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMTApCiAgKSArCiAgbGFicygKICAgIHggPSAnVG90YWwgZGUgcGVzc29hcycsCiAgICB5ID0gJ1Bhw61zJywKICAgIGZpbGwgPSAnJwogICkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQodmp1c3Q9MC41LCBhbmdsZSA9IDE1KQogICkKCmBgYApgYGB7cn0KZGYgJT4lIAogIHNlbGVjdChuYW1lcyhkZilbYyg3Njo3OSldKSAlPiUgCiAgZHJvcF9uYQpgYGAKCgpgYGB7cn0KbG9naXRfdXNlcl9mZWF0cyA8LSBjKCJRNSIsICJRNiIsICJRMTYiLCAiUTE3IiwgIlExOCIsICJRMTkiLCAiUTIzIiwgIlEyNCIsICJRMjYiLCAiUTI3IikKCmRmX2xvZ2l0IDwtIGRmICU+JSAKICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoIlExMV8iKSwgbmFtZXNfdG89IlBvdGVudGlhbCIsIHZhbHVlc190bz0iUG90ZW50aWFsX3ZhbHVlIikgJT4lIAogIG11dGF0ZSgKICAgIFBvdGVudGlhbCA9IGFzLmZhY3Rvcihhcy5udW1lcmljKHN0cl9leHRyYWN0KFBvdGVudGlhbCwgIihbMC05XSspJCIpKSksCiAgICBRMTcgPSBhcy5pbnRlZ2VyKFExNykKICApICU+JSAKICBkcm9wX25hKCJQb3RlbnRpYWxfdmFsdWUiKSAlPiUgCiAgc2VsZWN0KAogICAgbG9naXRfdXNlcl9mZWF0cywgc3RhcnRzX3dpdGgoIlE3XyIpLCBzdGFydHNfd2l0aCgiUThfIiksIAogICAgc3RhcnRzX3dpdGgoIlE5XyIpLCBzdGFydHNfd2l0aCgiUTEwXyIpLCBzdGFydHNfd2l0aCgiUTExXyIpLCAKICAgIHN0YXJ0c193aXRoKCJRMTNfIiksIHN0YXJ0c193aXRoKCJRMTRfIiksIHN0YXJ0c193aXRoKCJRMTVfIiksCiAgICBQb3RlbnRpYWwKICApICU+JSAKICBtdXRhdGVfYWxsKAogICAgZnVucyhhcy5udW1lcmljKC4pKQogICkgJT4lIAogIG11dGF0ZV9hbGwoCiAgICBmdW5zKHJlcGxhY2VfbmEoLiwgMCkpCiAgKSAlPiUgCiAgbXV0YXRlKAogICAgUG90ZW50aWFsID0gYXMuZmFjdG9yKFBvdGVudGlhbCkKICApCgpgYGAKCgpgYGB7cn0KZGYgJT4lIAogIGRyb3BfbmEoUTE3KSAlPiUgCiAgZ3JvdXBfYnkoUTE3KSAlPiUgCiAgY291bnQoKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKQpgYGAKCmBgYHtyfQpkZl9sb2dpdCAlPiUgCiAgc2VsZWN0KFBvdGVudGlhbCkgJT4lIAogIGdyb3VwX2J5KFBvdGVudGlhbCkgJT4lIAogIGNvdW50KCkgJT4lIAogIGFycmFuZ2UobikKICAKYGBgCiMjIyBMb2dpdAoKIyMjIyBUcmVpbmFuZG8gbyBtb2RlbG8KCmBgYHtyfQoKc2V0LnNlZWQoMTIzKQoKc3BsaXRzIDwtIHJzYW1wbGU6OmluaXRpYWxfc3BsaXQoZGZfbG9naXQpCnRyYWluIDwtIHJzYW1wbGU6OnRyYWluaW5nKHNwbGl0cykKdGVzdCA8LSByc2FtcGxlOjp0ZXN0aW5nKHNwbGl0cykKIApsb2dpdF9maXQgPC0gbm5ldDo6bXVsdGlub20oUG90ZW50aWFsIH4gLiwgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IHRyYWluLCBNYXhOV3RzPTEwMDAwKQoKYGBgCgoKIyMjIyBBdmFsaWFuZG8gbyBtb2RlbG8KCmBgYHtyfQoKeXRlc3QgPC0gdGVzdCAlPiUgCiAgc2VsZWN0KFBvdGVudGlhbCkKCnlwcmVkIDwtIHByZWRpY3QobG9naXRfZml0LCB0ZXN0ICU+JSAKICAgICAgICAgICAgICAgICAgIHNlbGVjdCgtUG90ZW50aWFsKSkKCk1MbWV0cmljczo6QWNjdXJhY3koeXByZWQsIHl0ZXN0JFBvdGVudGlhbCkKYGBgCgpTZSBmb3NzZW1vcyBjaHV0YXIgdW1hIGNsYXNzZSBkZW50cmUgYXMgMTIgcG9zc8OtdmVpcywgdGVyw61hbW9zIGAxLzEyYCBlbSBtw6lkaWEgZGUgYWNlcnRvcy4gSXNzbyDDqSBtZW5vciBxdWUgYSBhY3Vyw6FjaWEgb2J0aWRhLCBlbnTDo28gbm8gZ2VyYWwgbm9zc28gbW9kZWxvIGNvbnNlZ3VpdSBhcHJlbmRlciB1bSBwb3VjbyBzb2JyZSBvcyBkaWZlcmVudGVzIHBlcmZpcy4KCgpgYGB7cn0KcFJPQzo6cm9jKHJlc3BvbnNlID0geXRlc3QkUG90ZW50aWFsLCBwcmVkaWN0b3I9YXMubnVtZXJpYyh5cHJlZCkpICU+JSAKICBwbG90CmBgYAoKIyMjIENsdXN0ZXJpbmcKCmBgYHtyfQoKZGZfa20gPC0gZGZfbG9naXQgJT4lIAogIHNlbGVjdCgtUG90ZW50aWFsKQoKYGBgCgoKYGBge3J9CmFkanVzdF9rbWVhbnMgPC0gZnVuY3Rpb24oaykgewogIGtfZml0IDwtIGRmX2ttICU+JSAKICAgIGttZWFucyhrLCBpdGVyLm1heCA9IDMwKQogIAogIHcgPC0ga19maXQkdG90LndpdGhpbnNzCiAgdGliYmxlKGsgPSBrLCB3ID0gdykKfQoKa19hZGp1c3QgPC0gbWFwX2RmcigyOjEwLCBhZGp1c3Rfa21lYW5zKQpgYGAKCmBgYHtyfQprX2FkanVzdCAlPiUgCiAgZ2dwbG90KAogICAgYWVzKAogICAgICB4ID0gaywgCiAgICAgIHkgPSB3CiAgICApCiAgKSArIAogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICJyZWQiLCBzaXplID0gMykgKwogIHRoZW1lX21pbmltYWwoMTIpCmBgYAoKSXJlbW9zIHNlcGFyYXIgZW0gNSBncnVwb3MuLi4KCmBgYHtyfQoKa19hZGogPC0gZGZfa20gJT4lIAogIGttZWFucyg1LCBpdGVyLm1heCA9IDMwKQoKYGBgCgpgYGB7cn0KZGZfa20kY2x1c3RlciA9IGtfYWRqJGNsdXN0ZXIKYGBgCgpgYGB7cn0KZGZfa20gPC0gZGZfa20gJT4lIAogIG11dGF0ZSgKICAgIGNsdXN0ZXIgPSBhcy5mYWN0b3IoY2x1c3RlcikKICApCmBgYAoKIyMjIyBBbmFsaXNhbmRvIGdydXBvcwoKIyMjIyMgRnJlcXVlbmNpYSBkZSB1c28KCmBgYHtyfQoKZGZfa20gJT4lIAogIHNlbGVjdChRNSwgY2x1c3RlcikgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgbXV0YXRlKAogICAgUTUgPSBxNV9hbnN3ZXJzW1E1LF0KICApICU+JSAKICBncm91cF9ieShRNSwgY2x1c3RlcikgJT4lIAogICAgY291bnQoKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUgCiAgZ2dwbG90KAogICAgYWVzKAogICAgICB4ID0gcmVvcmRlcihRNSwgLW4pLAogICAgICB5ID0gbiwKICAgICAgZmlsbCA9IGNsdXN0ZXIKICAgICkKICApICsKICBnZW9tX2JhcigKICAgIHN0YXQgPSAiaWRlbnRpdHkiLAogICAgcG9zaXRpb24gPSAiZmlsbCIKICApICsKICBsYWJzKAogICAgeSA9ICdGcmVxdcOqbmNpYSBkZSBhY2Vzc28gw6AgbG9qYSBkZSBhcGxpY2F0aXZvcycsCiAgICB4ID0gJ1RvdGFsJwogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyMCwgdmp1c3QgPSAwLjUpLAogICkKYGBgCgpDb25zZWd1aW1vcyB2ZXIgcXVlIDIgZ3J1cG9zIHBhcmVjZW0gYWNlc3NhciBtYWlzIGEgbG9qYSBkbyBxdWUgb3MgZGVtYWlzLi4uIAoKVmlzdWFsaXphcmVtb3MgYSBjb3JyZWxhw6fDo286CgpgYGB7cn0KY29yKGRmX2ttJFE1LCBkZl9rbSRjbHVzdGVyKQpgYGAKClF1YW50byBtYWlvciBvIHVzbywgbWVub3IgbyBjbHVzdGVyLi4uIMOpIG8gcXVlIGNvbnNlZ3VpbW9zIHZlciB0YW1iw6ltIGVtIG5vc3NvIGdyw6FmaWNvLgoKUHJvc3NlZ3VpcmVtb3MuLi4KCmBgYHtyfQptYWtlX2NvdW50X2Zyb21fcXVlc3Rpb24gPC0gZnVuY3Rpb24gKGRmLCBjb2wsIG5hbWVzX3RvID0gImNvbHVtbiIsIHZhbHVlc190byA9ICJjb2x1bW5fdmFsdWUiKSB7CiAgZGYgJT4lIAogICAgc2VsZWN0KHN0YXJ0c193aXRoKGNvbCksIGNsdXN0ZXIpICU+JSAKICAgIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoY29sKSwgbmFtZXNfdG8gPSBuYW1lc190bywgdmFsdWVzX3RvID0gdmFsdWVzX3RvKQp9CgpyZWdleF9vbmx5X251bWJlcnMgPSAnKFswLTldKSQnCmBgYAoKCiMjIyMgTyBxdWUgbW90aXZhIGFzIHBlc3NvYXMgZGUgY2FkYSB1bSBkb3MgZ3J1cG9zIGEgcHJvY3VyYXIgcG9yIGFwbGljYXRpdm8/CgpgYGB7cn0KZGZfa20gJT4lIAogIHNlbGVjdChzdGFydHNfd2l0aCgiUTdfIiksIGNsdXN0ZXIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJRN18iKSwgbmFtZXNfdG8gPSAibW90aXZvIiwgdmFsdWVzX3RvID0gInZhbG9yX21vdGl2byIpICU+JSAKICBtdXRhdGUoCiAgICBtb3Rpdm9fbiA9IHN0cl9leHRyYWN0KG1vdGl2bywgJyhbMC05XSkkJykKICApICU+JSAKICBmaWx0ZXIodmFsb3JfbW90aXZvID09IDEpICU+JQogIGdyb3VwX2J5KGNsdXN0ZXIsIG1vdGl2bykgJT4lIAogIGNvdW50KCkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ2dwbG90KAogICAgYWVzKAogICAgICB4ID0gbW90aXZvLAogICAgICB5ID0gbiwKICAgICAgZmlsbCA9IGNsdXN0ZXIsCiAgICAgIGxhYmVsID0gbgogICAgKQogICkgKwogIGdlb21fYmFyKAogICAgc3RhdCA9ICJpZGVudGl0eSIsCiAgICBwb3NpdGlvbiA9ICJmaWxsIgogICkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgICBsYWJlbHMgPSBxN19uYW1lcwogICkgICsKICBsYWJzKAogICAgeCA9ICdNb3Rpdm8nLAogICAgeSA9ICdQb3JjZW50YWdlbScKICApICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjAsIHZqdXN0ID0gMC41KSwKICApIAoKYGBgCk9zIGdydXBvcyBwYXJlY2VtIHRlciB1bWEgZGlzdHJpYnVpw6fDo28gaG9tb2dlbmVhIG5vIHF1ZSBkaXogcmVzcGVpdG8gYXMgcmF6w7VlcyBwb3IgYmFpeGFzIGFwbGljYXRpdm8uIAoKIyMjIyBPIHF1ZSBhcyBwZXNzb2FzIGRvcyBncnVwb3MgY29uc2lkZXJhbSBwYXJhIGJhaXhhciB1bSBhcGxpY2F0aXZvPwoKYGBge3J9CgpzZWxlY3QoZGZfa20sIHN0YXJ0c193aXRoKCJRN18iKSwgY2x1c3RlcikgJT4lIAogIG1ha2VfY291bnRfZnJvbV9xdWVzdGlvbigiUTdfIiwgIm1vdGl2byIsICJ2YWxvcl9tb3Rpdm8iKSAlPiUgCiAgbXV0YXRlKAogICAgbW90aXZvID0gc3RyX2V4dHJhY3QobW90aXZvLCByZWdleF9vbmx5X251bWJlcnMpCiAgKSAlPiUgCiAgZmlsdGVyKHZhbG9yX21vdGl2byA9PSAxKSAlPiUgCiAgZ3JvdXBfYnkoY2x1c3RlciwgbW90aXZvKSAlPiUgCiAgY291bnQoKSAlPiUKICBnZ3Bsb3QoCiAgICBhZXMoCiAgICAgIHggPSBtb3Rpdm8sCiAgICAgIHkgPSBuLAogICAgICBmaWxsID0gY2x1c3RlcgogICAgKQogICkgKwogIGdlb21fYmFyKAogICAgc3RhdCA9ICJpZGVudGl0eSIsCiAgICBwb3NpdGlvbiA9ICJmaWxsIgogICkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgICBsYWJlbHMgPSBxOV9uYW1lcwogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxMCwgdmp1c3QgPSAuNikKICApCmBgYAoK